{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Gates in Qiskit\n",
    "Start by some typical setup and definition of useful functions, which you are encouraged to look at.\n",
    "\n",
    "Then, head to the [exercises start](#Exercises-Start-Here) to start coding!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister\n",
    "from qiskit import execute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Choose the drawer you like best:\n",
    "from qiskit.tools.visualization import matplotlib_circuit_drawer as draw\n",
    "#from qiskit.tools.visualization import circuit_drawer as draw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import IBMQ\n",
    "IBMQ.load_account() # make sure you have setup your token locally to use this"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Utils for visualizing experimental results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def show_results(D):\n",
    "    # D is a dictionary with classical bits as keys and count as value\n",
    "    # example: D = {'000': 497, '001': 527}\n",
    "    plt.bar(range(len(D)), list(D.values()), align='center')\n",
    "    plt.xticks(range(len(D)), list(D.keys()))\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Utils for executing circuits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import Aer\n",
    "# See a list of available local simulators\n",
    "print(\"Aer backends: \", Aer.backends())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# see a list of available remote backends (these are freely given by IBM)\n",
    "print(\"IBMQ Backends: \", IBMQ.backends())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Execute locally"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# execute circuit and either display a histogram of the results\n",
    "def execute_locally(qc, draw_circuit=False):\n",
    "    # Compile and run the Quantum circuit on a simulator backend\n",
    "    backend_sim = Aer.get_backend('qasm_simulator')\n",
    "    job_sim = execute(qc, backend_sim)\n",
    "    result_sim = job_sim.result()\n",
    "    result_counts = result_sim.get_counts(qc)\n",
    "    \n",
    "    # Print the results\n",
    "    print(\"simulation: \", result_sim, result_counts)\n",
    "    \n",
    "    if draw_circuit: # draw the circuit\n",
    "        draw(qc)\n",
    "    else: # or show the results\n",
    "        show_results(result_counts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Execute remotely"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit.backends.ibmq import least_busy\n",
    "import time\n",
    "# Compile and run on a real device backend\n",
    "def execute_remotely(qc, draw_circuit=False):\n",
    "    if draw_circuit: # draw the circuit\n",
    "        draw(qc)\n",
    "    try:\n",
    "        # select least busy available device and execute.\n",
    "        least_busy_device = least_busy(IBMQ.backends(simulator=False))\n",
    "        print(\"Running on current least busy device: \", least_busy_device)\n",
    "\n",
    "        # running the job\n",
    "        job_exp = execute(qc, backend=least_busy_device, shots=1024, max_credits=10)\n",
    "\n",
    "        lapse, interval = 0, 10\n",
    "        while job_exp.status().name != 'DONE':\n",
    "            print('Status @ {} seconds'.format(interval * lapse))\n",
    "            print(job_exp.status())\n",
    "            time.sleep(interval)\n",
    "            lapse += 1\n",
    "        print(job_exp.status())\n",
    "        exp_result = job_exp.result()\n",
    "        result_counts = exp_result.get_counts(qc)\n",
    "\n",
    "        # Show the results\n",
    "        print(\"experiment: \", exp_result, result_counts)\n",
    "        if not draw_circuit: # show the results\n",
    "            show_results(result_counts)\n",
    "    except:\n",
    "        print(\"All devices are currently unavailable.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building the circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def new_circuit(size):\n",
    "    # Create a Quantum Register with size qubits\n",
    "    qr = QuantumRegister(size)\n",
    "\n",
    "    # Create a Classical Register with size bits\n",
    "    cr = ClassicalRegister(size)\n",
    "\n",
    "    # Create a Quantum Circuit acting on the qr and cr register\n",
    "    return qr, cr, QuantumCircuit(qr, cr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<h1 align=\"center\">Exercises Start Here</h1>\n",
    "\n",
    "Make sure you ran all the above cells in order, as the following exercises use functions defined and imported above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding Gates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Hadamard\n",
    "This gate is required to make superpositions.\n",
    "\n",
    "**TASK:** Create a new circuit with 2 qubits using `new_circuit` (very useful to reconstruct your circuit in Jupyter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Add a Hadamard on the _least important_ qubit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# H gate on qubit 0\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Perform a measurement on that qubit to the first bit in the register"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure the specific qubit\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** check the result using `execute_locally` test both `True` and `False` for the `draw_circuit` option"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The result should be something like `COMPLETED {'00': 516, '01': 508}`.\n",
    "\n",
    "**TASK:** What does this mean?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> That we got our superposition as expected, approximately 50% of the experiments yielded 0 and the other 50% yielded 1."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### X Gate (Pauli-X)\n",
    "This gate is also referred to as a bit-flip.\n",
    "\n",
    "\n",
    "**TASK:** Create a new circuit with 2 qubits using `new_circuit` (very useful to reconstruct your circuit in Jupyter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Add an X gate on the _most important_ qubit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# H gate on qubit 1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Perform a measurement on that qubit to the first bit in the register"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure the specific qubit\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** check the result using `execute_locally` test both `True` and `False` for the `draw_circuit` option"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Free flow\n",
    "At this stage you are encouraged to repeat (and tweek as you wish) the above tasks for the Hadamard and X gates, especially on single qubit gates."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### CNOT (Controlled NOT, Controlled X gate)\n",
    "This gate uses a control qubit and a target qubit to \n",
    "\n",
    "\n",
    "**TASK:** Create a new circuit with 2 qubits using `new_circuit` (very useful to reconstruct your circuit in Jupyter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Add a CNOT gate with the _least important_ qubit as the control and the other as the target"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# CNOT gate\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Perform a measurement on the qubits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure the specific qubit\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** check the result using `execute_locally` test both `True` and `False` for the `draw_circuit` option"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Since a single CNOT does not seem very powerful, go ahead and add a hadamard gate to the two qubits (before the CNOT gate) and redo the experiment (you can try this by using a single Hadamard on each qubit as well)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# H gate on 2 qubits\n",
    "\n",
    "# CNOT gate\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Free flow: Changing the direction of a CNOT gate\n",
    "Check this [application of the CNOT](https://github.com/Qiskit/ibmqx-user-guides/blob/master/rst/full-user-guide/004-Quantum_Algorithms/061-Basic_Circuit_Identities_and_Larger_Circuits.rst#changing-the-direction-of-a-cnot-gate) and try to replicate it using Qiskit!\n",
    "\n",
    "Try to replicate it using the unitary transformations as well, pen and paper is better suited for this.\n",
    "\n",
    "![diagram of the problem](reverse_cnot.png)\n",
    "\n",
    "A CNOT equals Hadamards on both qubits an oposite CNOT and two new Hadamards!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Free flow: Swapping the states of qubits with a CNOT gate\n",
    "Check this [application of the CNOT](https://github.com/Qiskit/ibmqx-user-guides/blob/master/rst/full-user-guide/004-Quantum_Algorithms/061-Basic_Circuit_Identities_and_Larger_Circuits.rst#swapping-the-states-of-qubits) and try to replicate it using Qiskit! \n",
    "\n",
    "Try to replicate it using the unitary transformations as well, pen and paper is better suited for this.\n",
    "\n",
    "![diagram of the problem](swap_with_cnot.png)\n",
    "\n",
    "Three CNOT gates allow 2 qubits to swap their original values, can you do this with 2 classical bits??"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Executing on a remote device\n",
    "If you do this, you may have to wait for some time (usually a few minutes), depending on the current demand of the devices\n",
    "\n",
    "**TASK:** Create a circuit that simply measures 5 qubits and run it on a remote device using `execute_remotely`!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# execute_remotely(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Comment on the results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> \n",
    "**Important:** Once you get the results, you may see that, in fact, most of the iterations resulted in `00000`, but you will also see that there will be a few hits on other bit configurations (typically mostly composed of `0`s, like `00001` or `00010`) this is due to **experimental error** on the quantum device and is a concern to take into account when deploying into real devices!!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
